/*
 * buffer.cpp
 *
 *  Created on: 06.04.2010
 *      Author: Florian Gref
 *
 */
#include"../buffer/buffer.h"


Buffer::Buffer(char* src, char* out) {
	this->buffer1 = new char[BUFFER_SIZE];
	this->buffer2 = new char[BUFFER_SIZE];
	this->bufferLoaded = false;
	this->position = 0;
	this->endOfFileNear=false;
	this->current_ptr = NULL;
	this->wentBack = false;
	this->text = new char[BUFFER_SIZE];
	number = new char[1000];
	if ((this->out_ptr = fopen(out, "w")) == NULL) {
		perror("Unable to open the sourcefile, Buffer");
	}

	if ((this->src_ptr = fopen(src, "rb")) == NULL) {
		perror("Unable to open the sourcefile, Buffer");
	} else {
		load();
	}

}

Buffer::~Buffer() {
	fclose(this->src_ptr);
	fclose(this->out_ptr);
	delete[] this->buffer1;
	delete[] this->buffer2;
	delete[] this->number;
}

void Buffer::load() {
	/*
	 * Block bis rewind dient Größenerkennung
	 */
	fseek(src_ptr, 0, SEEK_END);
	this->src_size = ftell(src_ptr);
	std::cout << "The file, you've opened consists of " << src_size
			<< " characters\n";
	rewind(src_ptr);

	this->current_ptr = this->buffer1;
	buffer();

}

char Buffer::getChar() {
	changeBuffer();
	return current_ptr[position++];
}

void Buffer::buffer() {
	this->charCount = fread(current_ptr, 1, BUFFER_SIZE, this->src_ptr);
}

void Buffer::changeBuffer() {
	if (position == BUFFER_SIZE) {
		if (current_ptr == buffer1) {
			//std::cout << "[Buffer 2]";
			current_ptr = buffer2;
		} else {
			current_ptr = buffer1;
			//std::cout << "[Buffer 1]";
		}
		this->bufferLoaded = true;
		position = 0;
		if (!wentBack) {
			buffer();
		}
		wentBack = false;
	}

	if (position == charCount && !wentBack) {

		endOfFileNear = true;
		throw noMoreChar_exception();
		exit(0);
	}
}

char* Buffer::tokentypeToString(tokentype t) {
	char* type;
	switch (t) {
	case TOKEN_BRACE_CLOSE:
		type = "TOKEN BRACE CLOSE           ";
		break;
	case TOKEN_AND:
	    type = "TOKEN AND                   ";
		break;
	case TOKEN_BRACE_OPEN:
		type = "TOKEN BRACE OPEN            ";
		break;
	case TOKEN_DIVIDE:
		type = "TOKEN DIVIDE                ";
		break;
	case TOKEN_MINUS:
		type = "TOKEN MINUS                 ";
		break;
	case TOKEN_MULTIPLIE:
		type = "TOKEN MULTIPLIE             ";
		break;
	case TOKEN_PLUS:
		type = "TOKEN PLUS                  ";
		break;
	case TOKEN_SEMICOLON:
		type = "TOKEN SEMICOLON             ";
		break;
	case TOKEN_SQUARED_BRACKET_CLOSE:
		type = "TOKEN SQUARED BRACKET CLOSE ";
		break;
	case TOKEN_SQUARED_BRACKET_OPEN:
		type = "TOKEN SQUARED BRACKET OPEN  ";
		break;
	case TOKEN_SIGN:
		type = "TOKEN SIGN                  ";
		break;
	case TOKEN_READ:
		type = "TOKEN READ                  ";
		break;
	case TOKEN_PRINT:
		type = "TOKEN PRINT                 ";
		break;
	case TOKEN_INTEGER:
		type = "TOKEN INTEGER               ";
		break;
	case TOKEN_IDENTYFIER:
		type = "TOKEN IDENTIFIER            ";
		break;
	case TOKEN_ERROR:
		type = "TOKEN ERROR                 ";
		break;
	case TOKEN_COMMENT_NOT_CLOSED:
		type = "TOKEN NOT CLOSED            ";
		break;
	case TOKEN_CURLY_BRACKET_CLOSE:
		type = "TOKEN CURLY BRACKET CLOSE   ";
		break;
	case TOKEN_CURLY_BRACKET_OPEN:
		type = "TOKEN CURLY BRACKET OPEN    ";
		break;
	case TOKEN_FACTORIAL:
		type = "TOKEN FACTORIAL             ";
		break;
	case TOKEN_FUCHS:
		type = "TOKEN FUCHS                 ";
		break;
	case TOKEN_GREATER:
		type = "TOKEN GREATER               ";
		break;
	case TOKEN_LESS:
		type = "TOKEN LESS                  ";
		break;
	case TOKEN_EQUAL:
		type = "TOKEN EQUAL                 ";
		break;
	}
	return type;
}

char* Buffer::numberToChar(long int n) {

	number = itoa(n, number, 10);
	return number;
}

void Buffer::insertTab(int index, char* array) {
	array[index] = '\t';
}

void Buffer::writeTokentypeToFile(tokentype t, int nLine, int nColumn,
		char* lexem) {

	int i = 0;
	char* type=tokentypeToString(t);
	while (type[i] != '\0') {
		text[i] = type[i];
		i++;
	}

	for (int tab = 0; tab < 1; tab++) {
		insertTab(i++, text);
	}
	text[i++] = 'L';
	text[i++] = 'I';
	text[i++] = 'N';
	text[i++] = 'E';
	text[i++] = ' ';
	text[i++] = ':';
	text[i++] = ' ';
	for (int j = 0; numberToChar(nLine)[j] != '\0'; j++) {
		text[i] = numberToChar(nLine)[j];
		i++;
	}

	for (int tab = 0; tab < 2; tab++) {
		insertTab(i++, text);
	}

	text[i++] = 'C';
	text[i++] = 'O';
	text[i++] = 'L';
	text[i++] = 'U';
	text[i++] = 'M';
	text[i++] = 'N';
	text[i++] = ' ';
	text[i++] = ':';
	text[i++] = ' ';

	for (int j = 0; numberToChar(nColumn)[j] != 0; j++) {
		text[i] = numberToChar(nColumn)[j];
		i++;
	}

	if (t == TOKEN_IDENTYFIER && lexem != 0) {

		for (int j = 0; j < 2; j++) {
			insertTab(i++, text);
		}
		text[i++]='L';
		text[i++]='E';
		text[i++]='X';
		text[i++]='E';
		text[i++]='M';
		text[i++]=' ';
		text[i++]=':';
		text[i++]=' ';
		for (int j = 0; lexem[j] != '\0'; j++) {
			text[i++] = lexem[j];
		}
	}
	text[i++] = '\n';
	//text[i++] = '\0';


	if(!i== fwrite ( text, 1, i, out_ptr ))
	{
		perror("Unable to write the Output File, Buffer");
	}

	i = 0;


}

void Buffer::writeTokentypeToFile(tokentype t, int nLine, int nColumn,
		long wert) {

	int i = 0;
	char* type=tokentypeToString(t);
	while (type[i] != '\0') {
		text[i] = type[i];
		i++;
	}

	for (int tab = 0; tab < 1; tab++) {
		insertTab(i++, text);
	}
	text[i++] = 'L';
	text[i++] = 'I';
	text[i++] = 'N';
	text[i++] = 'E';
	text[i++] = ' ';
	text[i++] = ':';
	text[i++] = ' ';
	for (int j = 0; numberToChar(nLine)[j] != '\0'; j++) {
		text[i] = numberToChar(nLine)[j];
		i++;
	}

	for (int tab = 0; tab < 2; tab++) {
		insertTab(i++, text);
	}

	text[i++] = 'C';
	text[i++] = 'O';
	text[i++] = 'L';
	text[i++] = 'U';
	text[i++] = 'M';
	text[i++] = 'N';
	text[i++] = ' ';
	text[i++] = ':';
	text[i++] = ' ';

	for (int j = 0; numberToChar(nColumn)[j] != 0; j++) {
		text[i] = numberToChar(nColumn)[j];
		i++;
	}

	if (t == TOKEN_INTEGER) {

		for (int j = 0; j < 2; j++) {
			insertTab(i++, text);
		}
		text[i++]='W';
		text[i++]='E';
		text[i++]='R';
		text[i++]='T';
		text[i++]=' ';
		text[i++]=' ';
		text[i++]=':';
		text[i++]=' ';
		for (int j = 0; numberToChar(wert)[j] != 0; j++) {
				text[i] = numberToChar(wert)[j];
				i++;
			}
	}
	text[i++] = '\n';
	//text[i++] = '\0';


	if(!i== fwrite ( text, 1, i, out_ptr ))
	{
		perror("Unable to write the Output File, Buffer");
	}

	i = 0;


}

void Buffer::ungetChar() {
	if (position == 0 && (!this->bufferLoaded)) {
		throw unableToGoBackException();
	} else {
		if (position > 0) {
			position--;
		} else {
			if (!wentBack) {
				if (current_ptr == buffer1) {
					//std::cout << "[RETURN BUFFER 2]";
					current_ptr = buffer2;
				} else {
					//std::cout << "[RETURN BUFFER 1]";
					current_ptr = buffer1;
				}
				this->bufferLoaded = false;
				position = BUFFER_SIZE - 1;
				wentBack = true;
			} else {
				throw unableToGoBackException();
			}
		}
	}
}
